#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdbool.h>




typedef struct
{
    int key;
    int val;
    UT_hash_handle hh;
} HashItem;

HashItem* hashFindItem(HashItem** obj, int key)
{
    HashItem* pEntry = NULL;
    HASH_FIND_INT(*obj, &key, pEntry);
    return pEntry;
}

bool hashAddItem(HashItem** obj, int key, int val)
{
    if (hashFindItem(obj, key))
    {
        return false;
    }
    HashItem* pEntry = (HashItem*)malloc(sizeof(HashItem));
    pEntry->key = key;
    pEntry->val = val;
    HASH_ADD_INT(*obj, key, pEntry);
    return true;
}

bool hashSetItem(HashItem** obj, int key, int val)
{
    HashItem* pEntry = hashFindItem(obj, key);
    if (!pEntry)
    {
        hashAddItem(obj, key, val);
    }
    else
    {
        pEntry->val = val;
    }
    return true;
}

int hashGetItem(HashItem** obj, int key, int defaultVal)
{
    HashItem* pEntry = hashFindItem(obj, key);
    if (!pEntry)
    {
        return defaultVal;
    }
    return pEntry->val;
}

void hashFree(HashItem** obj)
{
    HashItem* curr = NULL, * tmp = NULL;
    HASH_ITER(hh, *obj, curr, tmp)
    {
        HASH_DEL(*obj, curr);
        free(curr);
    }
}

int tupleSameProduct(int* nums, int numsSize)
{
    int ans = 0;
    HashItem* cnt = NULL;
    for (int i = 0; i < numsSize; i++)
    {
        for (int j = i + 1; j < numsSize; j++)
        {
            hashSetItem(&cnt, nums[i] * nums[j], hashGetItem(&cnt, nums[i] * nums[j], 0) + 1);
        }
    }
    for (HashItem* pEntry = cnt; pEntry; pEntry = pEntry->hh.next)
    {
        int val = pEntry->val;
        ans += val * (val - 1) * 4;
    }
    hashFree(&cnt);
    return ans;
}
